﻿using System;
using System.Collections;
using System.Data;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Web.UI;
using System.Web.UI.WebControls;
using Framework.Library.Data.DAL.JObject;

namespace Framework.Portal.Layouts.Admin.Components.Infomation
{
    public partial class SystemInfo : UserControl
    {
        private readonly string MENUNAME = string.Empty;

        public SystemInfo()
        {
        }

        public SystemInfo(JSection section)
        {
            MENUNAME = section.title;
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            lblCommandName.Text = MENUNAME;
            GetSystemInfo();
            rptMemoryInformation.DataSource = GetSystemMemoryInfo("Memory Information");
            rptProcessorInformation.DataSource = GetSystemProcessorInfo("Processor Information");
            rptStorageInformation.DataSource = GetSystemStorageInfo("Storage Information");
            rptMemoryInformation.DataBind();
            rptProcessorInformation.DataBind();
            rptStorageInformation.DataBind();
        }

        protected void rptInfomation_ItemDataBound(object sender, RepeaterItemEventArgs e)
        {
            if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
            {
                var curData = (DataRowView) e.Item.DataItem;
                var lblText = (Label) e.Item.FindControl("lblText");
                var lblValue = (Label) e.Item.FindControl("lblValue");
                lblValue.Text = curData["Value"].ToString();
                lblText.Text = curData["Name"].ToString();
            }
        }

        #region Get Information Function

        private void GetSystemInfo()
        {
            Label2.Text = Server.MachineName;
            Label1.Text = Request.ServerVariables["LOCAl_ADDR"];
            Label3.Text = Request.ServerVariables["Server_Name"];
            Label4.Text = Request.ServerVariables["Server_Port"];
            Label5.Text = Request.ServerVariables["Server_SoftWare"];
            Label6.Text = Request.FilePath;
            Label7.Text = Request.PhysicalPath;
            Label8.Text = Request.ApplicationPath;
            Label9.Text = Request.PhysicalApplicationPath;
            //	Platform
            OperatingSystem osInfo = Environment.OSVersion;
            Label10.Text = osInfo.ToString();
            Label11.Text = Environment.SystemDirectory;
            Label12.Text = Environment.Version.ToString();
            Label13.Text = CultureInfo.InstalledUICulture.EnglishName;
            Label14.Text = DateTime.Now.ToString();
            Label15.Text = TimeSpan.FromMilliseconds(Environment.TickCount).ToString();
            Label16.Text = TimeSpan.FromSeconds(Server.ScriptTimeout).ToString();
        }

        private DataTable GetSystemInfo(string tableName)
        {
            DataTable table = GenerateDataTable(tableName);
            //	Server Name
            Assign(table, tableName, string.Empty);
            Assign(table, "Server Name", Server.MachineName);
            Assign(table, "Server IP", Request.ServerVariables["LOCAl_ADDR"]);
            Assign(table, "Server Domain", Request.ServerVariables["Server_Name"]);
            Assign(table, "Server Port", Request.ServerVariables["Server_Port"]);
            //	Web Server
            Assign(table, "Web Server Version", Request.ServerVariables["Server_SoftWare"]);
            //	Path
            Assign(table, "Virtual Request Path", Request.FilePath);
            Assign(table, "Physical Request Path", Request.PhysicalPath);
            Assign(table, "Virtual Application Root Path", Request.ApplicationPath);
            Assign(table, "Physical Application Root Path", Request.PhysicalApplicationPath);
            //	Platform
            var os = new OperatingSystem(PlatformID.Win32Windows, new Version("6.1.7600"));
            OperatingSystem osInfo = Environment.OSVersion;
            Assign(table, "Operating System", osInfo.ToString());
            Assign(table, "Operating System Installation Directory", Environment.SystemDirectory);
            Assign(table, ".Net Version", Environment.Version.ToString());
            Assign(table, ".Net Language", CultureInfo.InstalledUICulture.EnglishName);
            Assign(table, "Server Current Time", DateTime.Now.ToString());
            Assign(table, "System Uptime", TimeSpan.FromMilliseconds(Environment.TickCount).ToString());
            Assign(table, "Script Timeout", TimeSpan.FromSeconds(Server.ScriptTimeout).ToString());
            return table;
        }

        private void GetSystemStorageInfo_DriveInfo(DataTable table)
        {
            try
            {
                Type typeDriveInfo = Type.GetType("System.IO.DriveInfo");
                MethodInfo get_drives = typeDriveInfo.GetMethod("GetDrives");
                object result = get_drives.Invoke(null, null);

                foreach (object o in (IEnumerable) result)
                {
                    try
                    {
                        //  Use reflection to call DriveInfo.GetProperties() to make 1.x compiler don't complain.
                        PropertyInfo[] props = typeDriveInfo.GetProperties();
                        var is_ready = (bool) typeDriveInfo.GetProperty("IsReady").GetValue(o, null);
                        string name = string.Empty;
                        string volume_label = string.Empty;
                        string drive_format = string.Empty;
                        string drive_type = string.Empty;
                        ulong total_free_space = 0;
                        ulong total_space = 0;
                        foreach (PropertyInfo prop in props)
                        {
                            switch (prop.Name)
                            {
                                case "Name":
                                    name = (string) prop.GetValue(o, null);
                                    break;
                                case "VolumeLabel":
                                    if (is_ready)
                                        volume_label = (string) prop.GetValue(o, null);
                                    break;
                                case "DriveFormat":
                                    if (is_ready)
                                        drive_format = (string) prop.GetValue(o, null);
                                    break;
                                case "DriveType":
                                    drive_type = prop.GetValue(o, null).ToString();
                                    break;
                                case "TotalFreeSpace":
                                    if (is_ready)
                                        total_free_space = (ulong) (long) prop.GetValue(o, null);
                                    break;
                                case "TotalSize":
                                    if (is_ready)
                                        total_space = (ulong) (long) prop.GetValue(o, null);
                                    break;
                            }
                        }

                        string label = string.Empty;
                        string size = string.Empty;

                        if (is_ready)
                        {
                            label = string.Format("{0} - <{1}> [{2}] - {3,-10}", name, volume_label, drive_format,
                                                  drive_type);
                            if (total_space > 0 && total_space != ulong.MaxValue && total_space != int.MaxValue)
                            {
                                size = string.Format("Free {0} / Total {1}", FormatNumber(total_free_space),
                                                     FormatNumber(total_space));
                            }
                        }
                        else
                        {
                            label = string.Format("{0} {1,-10}", name, drive_type);
                        }
                        Assign(table, label, size);
                    }
                    catch (Exception)
                    {
                    }
                }
            }
            catch (Exception)
            {
            }
        }

        private void GetSystemStorageInfo_WMI(DataTable table)
        {
            try
            {
                //  Use reflection to call WMI to make Mono compiler don't complain about assembly reference
                Assembly dSystemManangement =
                    Assembly.Load(
                        "System.Management, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A");
                if (dSystemManangement == null) return;

                Type tManagementObjectSearcher = dSystemManangement.GetType("System.Management.ManagementObjectSearcher");
                if (dSystemManangement == null) return;

                MethodInfo mGet = tManagementObjectSearcher.GetMethod("Get", new Type[] {});

                ConstructorInfo ctor = tManagementObjectSearcher.GetConstructor(new[] {typeof (string)});

                object searcher = ctor.Invoke(new object[] {"Select * From Win32_LogicalDisk"});
                if (dSystemManangement == null) return;

                object disks = mGet.Invoke(searcher, null);

                //  ManagementObject
                Type tManagementObject = dSystemManangement.GetType("System.Management.ManagementObject");

                foreach (object disk in (IEnumerable) disks)
                {
                    try
                    {
                        PropertyInfo prop = tManagementObject.GetProperty("Item", new[] {typeof (string)});
                        var i_drive_type = (uint) prop.GetValue(disk, new object[] {"DriveType"});
                        string drive_type = string.Empty;
                        switch (i_drive_type)
                        {
                            case 1:
                                drive_type = "No Root Directory";
                                break;
                            case 2:
                                drive_type = "Removable Disk";
                                break;
                            case 3:
                                drive_type = "Local Disk";
                                break;
                            case 4:
                                drive_type = "Network Drive";
                                break;
                            case 5:
                                drive_type = "Compact Disc";
                                break;
                            case 6:
                                drive_type = "RAM Disk";
                                break;
                            default:
                                drive_type = "Unknown";
                                break;
                        }
                        var name = prop.GetValue(disk, new object[] {"Name"}) as string;
                        var volume_label = prop.GetValue(disk, new object[] {"VolumeName"}) as string;
                        var filesystem = prop.GetValue(disk, new object[] {"FileSystem"}) as string;

                        string free_space = string.Empty;
                        try
                        {
                            free_space = FormatNumber((ulong) prop.GetValue(disk, new object[] {"FreeSpace"}));
                        }
                        catch (Exception)
                        {
                        }

                        string total_space = string.Empty;
                        try
                        {
                            total_space = FormatNumber((ulong) prop.GetValue(disk, new object[] {"Size"}));
                        }
                        catch (Exception)
                        {
                        }

                        string left = string.Format("{0} - <{1}> [{2}] - {3,-10}",
                                                    name,
                                                    volume_label,
                                                    filesystem,
                                                    drive_type
                            );

                        string right = ((free_space == null || free_space == "")
                                            ? string.Empty
                                            : string.Format("Free {0} / Total {1}", free_space, total_space));

                        Assign(table, left, right);
                    }
                    catch (Exception exception)
                    {
                        Assign(table, "Exception Occurs", exception.ToString());
                    }
                }
            }
            catch (Exception exception)
            {
                Assign(table, "Exception Occurs", exception.ToString());
            }
        }

        private DataTable GetSystemStorageInfo(string tableName)
        {
            DataTable table = GenerateDataTable(tableName);
            try
            {
                Assign(table, "Logical Driver Information", string.Join(", ", Directory.GetLogicalDrives()));
            }
            catch (Exception)
            {
            }

            if (Environment.Version.Major >= 2)
            {
                GetSystemStorageInfo_DriveInfo(table);
            }
            else
            {
                if (Environment.OSVersion.Platform == PlatformID.Win32NT)
                {
                    GetSystemStorageInfo_WMI(table);
                }
            }

            return table;
        }

        private void GetSystemMemoryInfo_proc(DataTable table)
        {
            string name = "/proc/meminfo";
            if (File.Exists(name))
            {
                using (var reader = new StreamReader(name, Encoding.ASCII))
                {
                    var ht = new Hashtable();
                    string line = string.Empty;
                    while ((line = reader.ReadLine()) != null)
                    {
                        string[] item = line.Split(":".ToCharArray());
                        if (item.Length == 2)
                        {
                            string k = item[0].Trim();
                            string v = item[1].Trim();
                            ht.Add(k, v);
                        }
                    }
                    Assign(table, "Physical Memory Size", string.Format("{0}", ht["MemTotal"]));
                    Assign(table, "Physical Free Memory Size", string.Format("{0}", ht["MemFree"]));
                    Assign(table, "Swap Total Size", string.Format("{0}", ht["SwapTotal"]));
                    Assign(table, "Swap Free Size", string.Format("{0}", ht["SwapFree"]));
                }
            }
        }

        private DataTable GetSystemMemoryInfo(string tableName)
        {
            DataTable table = GenerateDataTable(tableName);
            Assign(table, "Current Working Set", FormatNumber((ulong) Environment.WorkingSet));
            try
            {
                if (Environment.OSVersion.Platform == PlatformID.Win32NT)
                {
                    SystemUtil.MemoryInfo memory = SystemUtil.Memory;

                    Assign(table, "Physical Memory Size", FormatNumber(memory.dwTotalPhys));
                    Assign(table, "Physical Free Memory Size", FormatNumber(memory.dwAvailPhys));
                    Assign(table, "PageFile Size", FormatNumber(memory.dwTotalPageFile));
                    Assign(table, "Available PageFile Size", FormatNumber(memory.dwAvailPageFile));
                    Assign(table, "Virtual Memory Size", FormatNumber(memory.dwTotalVirtual));
                    Assign(table, "Available Memory Size", FormatNumber(memory.dwAvailVirtual));
                    Assign(table, "Memory Load", string.Format("{0} %", memory.dwMemoryLoad.ToString("N")));
                }
                else if ((int) Environment.OSVersion.Platform > 3)
                {
                    GetSystemMemoryInfo_proc(table);
                }
            }
            catch (Exception)
            {
            }
            return table;
        }

        private void GetSystemProcessorInfo_WMI(DataTable table)
        {
            //  Use reflection to call WMI to make Mono compiler don't complain about assembly reference
            Assembly dSystemManangement =
                Assembly.Load("System.Management, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A");
            if (dSystemManangement == null) return;

            Type tManagementObjectSearcher = dSystemManangement.GetType("System.Management.ManagementObjectSearcher");
            if (dSystemManangement == null) return;

            MethodInfo mGet = tManagementObjectSearcher.GetMethod("Get", new Type[] {});

            ConstructorInfo ctor = tManagementObjectSearcher.GetConstructor(new[] {typeof (string)});

            object searcher = ctor.Invoke(new object[] {"Select * From Win32_Processor"});
            if (dSystemManangement == null) return;

            object processors = mGet.Invoke(searcher, null);

            //  ManagementObject
            Type tManagementObject = dSystemManangement.GetType("System.Management.ManagementObject");
            foreach (object processor in (IEnumerable) processors)
            {
                try
                {
                    try
                    {
                        PropertyInfo prop = tManagementObject.GetProperty("Item", new[] {typeof (string)});
                        var sb = new StringBuilder();
                        //  Unique ID
                        var name = (string) prop.GetValue(processor, new object[] {"Name"});
                        sb.Append(name);
                        //  Clock Speed
                        var clock_speed = (uint) prop.GetValue(processor, new object[] {"CurrentClockSpeed"});
                        //  Max Clock Speed
                        var max_clock_speed = (uint) prop.GetValue(processor, new object[] {"MaxClockSpeed"});
                        sb.AppendFormat(" - {0} MHz / {1} MHz", clock_speed, max_clock_speed);
                        //  Current Voltage
                        var i_current_voltage = (ushort) prop.GetValue(processor, new object[] {"CurrentVoltage"});
                        double current_voltage = 0;
                        if (((uint) i_current_voltage & 0x80) == 0)
                        {
                            current_voltage = (i_current_voltage & 0x7F)/10.0;
                        }
                        else
                        {
                            try
                            {
                                var caps = (uint) prop.GetValue(processor, new object[] {"VoltageCaps"});
                                switch (caps & 0xF)
                                {
                                    case 1:
                                        current_voltage = 5;
                                        break;
                                    case 2:
                                        current_voltage = 3.3;
                                        break;
                                    case 3:
                                        current_voltage = 2.9;
                                        break;
                                }
                            }
                            catch (Exception)
                            {
                            }
                        }
                        if (current_voltage > 0)
                        {
                            sb.AppendFormat(" - {0}v", current_voltage);
                        }
                        //  Load Percentage 
                        var load_percentage = (ushort) prop.GetValue(processor, new object[] {"LoadPercentage"});
                        sb.AppendFormat(" - Load = {0} %", load_percentage);
                        Assign(table, "Processor", sb.ToString());
                    }
                    catch (Exception exception)
                    {
                        Assign(table, "Exception Occurs", exception.ToString());
                    }
                }
                catch (Exception)
                {
                }
            }
        }

        private void GetSystemProcessorInfo_proc(DataTable table)
        {
            string name = "/proc/cpuinfo";
            if (File.Exists(name))
            {
                using (var reader = new StreamReader(name, Encoding.ASCII))
                {
                    var processors = new ArrayList();
                    var ht = new Hashtable();
                    string line = string.Empty;
                    while ((line = reader.ReadLine()) != null)
                    {
                        if (line.Trim().Length == 0)
                        {
                            processors.Add(ht);
                            ht = new Hashtable();
                        }
                        string[] item = line.Split(":".ToCharArray());
                        if (item.Length == 2)
                        {
                            string k = item[0].Trim();
                            string v = item[1].Trim();
                            ht.Add(k, v);
                        }
                    }

                    foreach (Hashtable processor in processors)
                    {
                        string n = string.Format("Processor {0}", processor["processor"]);
                        string v = string.Format("{0}{1}", processor["model name"],
                                                 (processor["cpu MHz"] != null)
                                                     ? string.Format(" - {0} MHz", processor["cpu MHz"])
                                                     : string.Empty);
                        Assign(table, n, v);
                    }
                }
            }
        }

        private DataTable GetSystemProcessorInfo(string tableName)
        {
            DataTable table = GenerateDataTable(tableName);
            try
            {
                if (Environment.OSVersion.Platform == PlatformID.Win32NT)
                {
                    Assign(table, "Number of Processors", Environment.GetEnvironmentVariable("NUMBER_OF_PROCESSORS"));
                    Assign(table, "Processor Id", Environment.GetEnvironmentVariable("PROCESSOR_IDENTIFIER"));
                    SystemUtil.CpuInfo cpu = SystemUtil.Cpu;
                    Assign(table, "Processor Type", cpu.dwProcessorType.ToString());
                    Assign(table, "Processor Level", cpu.dwProcessorLevel.ToString());
                    Assign(table, "Processor OEM Id", cpu.dwOemId.ToString());
                    Assign(table, "Page Size", cpu.dwPageSize.ToString());
                    GetSystemProcessorInfo_WMI(table);
                }
                else if ((int) Environment.OSVersion.Platform > 3)
                {
                    GetSystemProcessorInfo_proc(table);
                }
            }
            catch (Exception)
            {
            }
            return table;
        }

        #endregion

        #region Helper Methods

        private string FormatNumber(ulong value)
        {
            if (value < 4*1024)
            {
                return string.Format("{0} Bytes", value);
            }
            else if (value < (long) 4*1024*1024)
            {
                return string.Format("{0} KB", (value/(double) (1024)).ToString("N"));
            }
            else if (value < (long) 4*1024*1024*1024)
            {
                return string.Format("{0} MB", (value/(double) ((long) 1024*1024)).ToString("N"));
            }
            else if (value < (long) 4*1024*1024*1024*1024)
            {
                return string.Format("{0} GB", (value/(double) ((long) 1024*1024*1024)).ToString("N"));
            }
            else
            {
                return string.Format("{0} TB", (value/(double) ((long) 1024*1024*1024*1024)).ToString("N"));
            }
        }

        private DataTable GenerateDataTable(string name)
        {
            var table = new DataTable(name);
            table.Columns.Add("Name", typeof (string));
            table.Columns.Add("Value", typeof (string));
            return table;
        }

        private bool TestObject(string progID)
        {
            try
            {
                Server.CreateObject(progID);
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }

        private void Assign(DataTable table, string name, string value)
        {
            DataRow row = table.NewRow();
            row["Name"] = name;
            row["Value"] = value;
            table.Rows.Add(row);
        }

        #endregion
    }
}

public class SystemUtil
{
    public static MemoryInfo Memory
    {
        get
        {
            var obj = new MemoryInfo();
            GlobalMemoryStatus(ref obj);
            return obj;
        }
    }

    public static CpuInfo Cpu
    {
        get
        {
            var obj = new CpuInfo();
            GetSystemInfo(ref obj);
            return obj;
        }
    }

    [DllImport("kernel32", CharSet = CharSet.Auto, SetLastError = true)]
    internal static extern void GetSystemInfo(ref CpuInfo cpuinfo);

    [DllImport("kernel32", CharSet = CharSet.Auto, SetLastError = true)]
    internal static extern void GlobalMemoryStatus(ref MemoryInfo meminfo);

    #region Nested type: CpuInfo

    [StructLayout(LayoutKind.Sequential)]
    public struct CpuInfo
    {
        public uint dwOemId;
        public uint dwPageSize;
        public uint lpMinimumApplicationAddress;
        public uint lpMaximumApplicationAddress;
        public uint dwActiveProcessorMask;
        public uint dwNumberOfProcessors;
        public uint dwProcessorType;
        public uint dwAllocationGranularity;
        public uint dwProcessorLevel;
        public uint dwProcessorRevision;
    }

    #endregion

    #region Nested type: MemoryInfo

    [StructLayout(LayoutKind.Sequential)]
    public struct MemoryInfo
    {
        public uint dwLength;
        public uint dwMemoryLoad;
        public uint dwTotalPhys;
        public uint dwAvailPhys;
        public uint dwTotalPageFile;
        public uint dwAvailPageFile;
        public uint dwTotalVirtual;
        public uint dwAvailVirtual;
    }

    #endregion
}